package www.wen.com.common.lib.base.module

import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import www.wen.com.common.R
import www.wen.com.common.lib.data.entities.builtIn.LoadingDialog
import www.wen.com.common.lib.data.entities.builtIn.LoadingDialogStateType
import www.wen.com.common.lib.data.entities.builtIn.UiStateCustom
import www.wen.com.common.lib.data.repository.AppDataManager
import www.wen.com.common.lib.extension.getString
import www.wen.com.common.lib.data.entities.builtIn.Result
import javax.inject.Inject

/**
 * @author WEN
 * @Description: 这个类是方便写扩展函数，并且具有2个通用的核心网络请求封装
 * @date 2020/11/2 17:35
 */
@HiltViewModel
open class BaseApiViewModel @Inject constructor(var appDataManager: AppDataManager) : BaseViewModel(), LifecycleObserver {


    fun <T> requestUniversal(
        viewModelScope: CoroutineScope,
        request: suspend (appDataManager: AppDataManager) -> Result<T>,
        tipLoading: String = getString(R.string.loading),
        tipSuccess: String = getString(R.string.loading_succeeded),
        tipFail: String = getString(R.string.network_anomaly),
        isSendShowDialog: Boolean = true, //不显示任何弹窗和toast
        isShowSuccessDialogTip: Boolean = false, //请求成功后是否显示请求后 Dialog弹窗提示(isShowSuccessDialogTip为true的情况下isShowSuccessToastTip无效)
        isShowSuccessToastTip: Boolean = false, //请求成功后是否显示请求后toast提示,与isShowDialogTip的功能一样,只是一个是弱提示，一个是强提示
        isShowErrorDialogTip: Boolean = false, //请求失败后是否显示请求后 Dialog弹窗提示(isShowErrorDialogTip为true的情况下isShowErrorToastTip无效)
        isShowErrorToastTip: Boolean = true,//请求失败后是否显示请求后toast提示,与isShowDialogTip的功能一样,只是一个是弱提示，一个是强提示
        showResultDelay:Long = 1500, //显示强提示的时间
        showLoadingDelay:Long = 500, //显示加载弹窗的最短时间
        resultFailCall: ((String, Int) -> Unit)? = null, //失败回调
        resultSuccessCall: ((T?) -> Unit)? = null,
    ) {
        viewModelScope.launch {
            if (isSendShowDialog) {
                loading.value = UiStateCustom(
                    stateData = LoadingDialog(
                        tipLoading,
                        LoadingDialogStateType.LOADING
                    )
                )
            }
            val result = request.invoke(appDataManager)
            if (result is Result.Success) {
                if (isSendShowDialog) {
                    loading.value = UiStateCustom(
                        stateData = LoadingDialog(
                            tip = tipSuccess,
                            loadingDialogStateType = LoadingDialogStateType.SUCCESS,
                            isShowDialogTip = isShowSuccessDialogTip,
                            isShowToastTip = isShowSuccessToastTip,
                            showResultDelay = showResultDelay,
                            showLoadingDelay = showLoadingDelay,
                            action = {
                                resultSuccessCall?.invoke(result.data)
                            }
                        )
                    )
                } else {
                    resultSuccessCall?.invoke(result.data)
                }
            } else if (result is Result.Error) {
                if (isSendShowDialog) {
                    loading.value = UiStateCustom(
                        stateData = LoadingDialog(
                            tip = result.exception.message ?: tipFail,
                            loadingDialogStateType = LoadingDialogStateType.ERROR,
                            isShowDialogTip = isShowErrorDialogTip,
                            isShowToastTip = isShowErrorToastTip,
                            showResultDelay = showResultDelay,
                            showLoadingDelay = showLoadingDelay,
                            action = { resultFailCall?.invoke(result.exception.message ?: tipFail, result.code) }
                        )
                    )
                } else {
                    resultFailCall?.invoke(result.exception.message ?: tipFail, result.code)
                }
            }
        }
    }

    fun <T> requestUniversalFlow(
        universalFlow: (AppDataManager) -> Flow<T>,
        tipLoading: String = getString(R.string.loading),
        tipSuccess: String = getString(R.string.loading_succeeded),
        tipFail: String = getString(R.string.network_anomaly),
        isSendShowDialog: Boolean = true,
        isShowSuccessDialogTip: Boolean = false,
        isShowSuccessToastTip: Boolean = false,
        isShowErrorDialogTip: Boolean = false,
        isShowErrorToastTip: Boolean = true,
        showResultDelay:Long = 1500, //显示强提示的时间
        showLoadingDelay:Long = 500, //显示加载弹窗的最短时间
        resultFailCall: ((String) -> Unit)? = null,
        resultSuccessCall: ((T) -> Unit)? = null,
    ) {
        viewModelScope.launch {
            universalFlow.invoke(appDataManager)
                .onStart {
                    if (isSendShowDialog) {
                        loading.value = UiStateCustom(
                            stateData = LoadingDialog(tip = tipLoading, loadingDialogStateType = LoadingDialogStateType.LOADING)
                        )
                    }
                }
                .catch { cause ->
                    if (isSendShowDialog) {
                        loading.value = UiStateCustom(
                            stateData = LoadingDialog(
                                tip = cause.message ?: tipFail,
                                loadingDialogStateType = LoadingDialogStateType.ERROR,
                                isShowDialogTip = isShowErrorDialogTip,
                                isShowToastTip = isShowErrorToastTip,
                                showResultDelay = showResultDelay,
                                showLoadingDelay = showLoadingDelay,
                                action = { resultFailCall?.invoke(cause.message ?: tipFail) }
                            )
                        )
                    } else {
                        resultFailCall?.invoke(cause.message ?: tipFail)
                    }
                }
                .collect {
                    if (isSendShowDialog) {
                        loading.value = UiStateCustom(
                            stateData = LoadingDialog(
                                tip = tipSuccess,
                                loadingDialogStateType = LoadingDialogStateType.SUCCESS,
                                isShowDialogTip = isShowSuccessDialogTip,
                                isShowToastTip = isShowSuccessToastTip,
                                showResultDelay = showResultDelay,
                                showLoadingDelay = showLoadingDelay,
                                action = { resultSuccessCall?.invoke(it) }
                            )
                        )
                    } else {
                        resultSuccessCall?.invoke(it)
                    }
                }
        }
    }

}